//进行axios二次封装:使用请求与响应拦截器
import axios from 'axios'

import { AxiosRequestConfig } from 'axios'
// import { useRouter } from 'vue-router'
// import router from '@/router/router'
// const router = useRouter()
// 处理  类型“AxiosResponse<any, any>”上不存在属性“errorinfo
declare module 'axios' {
  interface AxiosResponse {
    errorinfo: null
    code: any
    msg: any
    body: any
    content: any
    // 这里追加你的参数
  }
  export function create(config?: AxiosRequestConfig): AxiosInstance
}

import { ElMessage, ElLoading } from 'element-plus'

let loading: any
// 内存中正在请求的数量
let loadingNum = 0
function startLoading() {
  if (loadingNum == 0) {
    loading = ElLoading.service({
      lock: true,
      text: '加载中...',
      // spinner: 'el-icon-loading',
    })
  }
  // 请求数量加1
  loadingNum++
}
function endLoading() {
  // 请求数量减1
  loadingNum--
  if (loadingNum <= 0) {
    loading.close()
  }
}
//引入用户相关的仓库
import useUserStore from '@/store/modules/user'

//第一步:利用axios对象的create方法,去创建axios实例(其他的配置:基础路径、超时的时间)
const request = axios.create({
  //基础路径
  baseURL: import.meta.env.VITE_APP_BASE_API + import.meta.env.VITE_API_URL, //基础路径上会携带/api
  timeout: 5000, //超时的时间的设置
})

request.defaults.headers.post['Content-Type'] =
  'application/json'
//第二步:request实例添加请求与响应拦截器
request.interceptors.request.use((config) => {
  const userStore = useUserStore()
  startLoading()
  removePending(config)
  addPending(config)

  if (config.data && config.data.data) {
    config.data = config.data.data
  }

  if (userStore.token) {
    // config.headers.Authorization = `Bearer ${userStore.token}`
    config.headers.Authorization = `${userStore.token}`
  }
  //config配置对象,headers属性请求头,经常给服务器端携带公共参数
  //返回配置对象
  return config
})

//第三步:响应拦截器
request.interceptors.response.use(
  (response) => {
    // const userStore = useUserStore()
    endLoading()
    //成功回调
    //简化数据
    removePending(response.config)

    // if (response.data.code === 403 || response.data?.data?.code === 403) {
    //   userStore.clearToken()
    //   router.replace({ name: 'login' })
    // }
    return response.data
  },
  (error) => {
    endLoading()
    //失败回调:处理http网络错误的
    //定义一个变量:存储网络错误信息
    httpErrorStatusHandle(error)
    return Promise.reject(error)
  }
)

/**
 * 处理异常
 * @param {*} error
 */
function httpErrorStatusHandle(error: any) {
  // 处理被取消的请求
  if (axios.isCancel(error)) return
  let message = error.response.data.msg

  if (error && error.response) {
    // switch (error.response.status) {
    //   case 302:
    //     message = '接口重定向了！'
    //     break
    //   case 400:
    //     message = '参数不正确！'
    //     break
    //   case 401:
    //     message = '您未登录，或者登录已经超时，请先登录！'
    //     break
    //   case 403:
    //     message = '登录凭证已失效，请重新登录！'
    //     break
    //   case 404:
    //     message = `请求地址出错: ${error.response.config.url}`
    //     break // 在正确域名下
    //   case 408:
    //     message = '请求超时！'
    //     break
    //   case 409:
    //     message = '系统已存在相同数据！'
    //     break
    //   case 500:
    //     // message = '服务器内部错误！'
    //     message = error?.response?.data?.message || '服务器内部错误！'
    //     break
    //   case 501:
    //     message = '服务未实现！'
    //     break
    //   case 502:
    //     message = '网关错误！'
    //     break
    //   case 503:
    //     message = '服务不可用！'
    //     break
    //   case 504:
    //     message = '服务暂时无法访问，请稍后再试！'
    //     break
    //   case 505:
    //     message = 'HTTP版本不受支持！'
    //     break
    //   default:
    //     message = '异常问题，请联系管理员！'
    //     break
    // }
  }
  if (error.message.includes('timeout')) message = '网络请求超时！'
  if (error.message.includes('Network'))
    message = window.navigator.onLine ? '服务端异常！' : '您断网了！'

  ElMessage({
    type: 'error',
    message,
  })
}

const pendingMap = new Map()

/**
 * 储存每个请求的唯一cancel回调, 以此为标识
 * @param {*} config
 */
function addPending(config: AxiosRequestConfig) {
  const pendingKey = getPendingKey(config)
  config.cancelToken =
    config.cancelToken ||
    new axios.CancelToken((cancel) => {
      if (!pendingMap.has(pendingKey)) {
        pendingMap.set(pendingKey, cancel)
      }
    })
}

/**
 * 删除重复的请求
 * @param {*} config
 */
function removePending(config: AxiosRequestConfig) {
  const pendingKey = getPendingKey(config)
  if (pendingMap.has(pendingKey)) {
    const cancelToken = pendingMap.get(pendingKey)
    // 如你不明白此处为什么需要传递pendingKey可以看文章下方的补丁解释
    cancelToken(pendingKey)
    pendingMap.delete(pendingKey)
  }
}

/**
 * 生成唯一的每个请求的唯一key
 * @param {*} config
 * @returns
 */
function getPendingKey(config: AxiosRequestConfig) {
  const { url, method, params } = config
  const { data } = config
  // if (typeof data === 'string') data = JSON.parse(data) // response里面返回的config.data是个字符串对象
  return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&')
}
//对外暴露
export default request
